////////////////////////////////////////////////////////////////////////////////
/// @file    oled.c
/// @author  AE TEAM
/// @brief   THIS FILE PROVIDES ALL THE SYSTEM FUNCTIONS.
////////////////////////////////////////////////////////////////////////////////
/// @attention
///
/// THE EXISTING FIRMWARE IS ONLY FOR REFERENCE, WHICH IS DESIGNED TO PROVIDE
/// CUSTOMERS WITH CODING INFORMATION ABOUT THEIR PRODUCTS SO THEY CAN SAVE
/// TIME. THEREFORE, MINDMOTION SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT OR
/// CONSEQUENTIAL DAMAGES ABOUT ANY CLAIMS ARISING OUT OF THE CONTENT OF SUCH
/// HARDWARE AND/OR THE USE OF THE CODING INFORMATION CONTAINED HEREIN IN
/// CONNECTION WITH PRODUCTS MADE BY CUSTOMERS.
///
/// <H2><CENTER>&COPY; COPYRIGHT MINDMOTION </CENTER></H2>
////////////////////////////////////////////////////////////////////////////////

// Define to prevent recursive inclusion
#define _OLED_C_

// Files includes
#include "hal_conf.h"
#include "oled.h"
#include "stdlib.h"
#include "oledfont.h"
#include "delay.h"


////////////////////////////////////////////////////////////////////////////////
/// @addtogroup MM32_Example_Layer
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup OLED
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup OLED_Exported_Constants
/// @{


// OLED video memory
// The storage format is as follows.
//[0]0 1 2 3 ... 127
//[1]0 1 2 3 ... 127
//[2]0 1 2 3 ... 127
//[3]0 1 2 3 ... 127
//[4]0 1 2 3 ... 127
//[5]0 1 2 3 ... 127
//[6]0 1 2 3 ... 127
//[7]0 1 2 3 ... 127
u8 OLED_GRAM[128][8];
////////////////////////////////////////////////////////////////////////////////
/// @brief  Update video memory to LCD
/// @param  None.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void OLED_Refresh_Gram(void)
{
    u8 i, n;
    for(i = 0; i < 8; i++) {
        OLED_WR_Byte (0xb0 + i, OLED_CMD);  // Set page address (0~7)
        OLED_WR_Byte (0x00, OLED_CMD);      // Set display location - column low address
        OLED_WR_Byte (0x10, OLED_CMD);      // Set display location - column height address
        for(n = 0; n < 128; n++) {
            OLED_WR_Byte(OLED_GRAM[n][i], OLED_DATA);
        }
    }
}
#if OLED_MODE==1


////////////////////////////////////////////////////////////////////////////////
/// @brief  write data to LCD
/// @param  data: The data to be written
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_WR_DATA(u16 data)
{
    *(vu16*)0x60000000 = data;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  write data to LCD
/// @param  regval: The data to be written
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_WR_REG(u16 regval)
{
    *(vu16*)(0x60000000 | (0x01 << 19)) = regval;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  write data to LCD
/// @param  data: The data to be written
/// @param  cmd command flag 0, indicating command; 1, represents data
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void OLED_WR_Byte(u8 dat, u8 cmd)
{
    if(cmd) {
        LCD_WR_REG(dat);
    }
    else {
        LCD_WR_DATA(dat);
    }
}
#endif


////////////////////////////////////////////////////////////////////////////////
/// @brief  Turn on OLED display
/// @param  data: The data to be written
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void OLED_Display_On(void)
{
    OLED_WR_Byte(0X8D, OLED_CMD); //SET DCDC
    OLED_WR_Byte(0X14, OLED_CMD); //DCDC ON
    OLED_WR_Byte(0XAF, OLED_CMD); //DISPLAY ON
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Turn off OLED display
/// @param  data: The data to be written
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void OLED_Display_Off(void)
{
    OLED_WR_Byte(0X8D, OLED_CMD); //SET DCDC
    OLED_WR_Byte(0X10, OLED_CMD); //DCDC OFF
    OLED_WR_Byte(0XAE, OLED_CMD); //DISPLAY OFF
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Clear the screen function,
/// @note   clear the screen, the entire screen is black!It's like not lighting up
/// @param  None
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void OLED_Clear(void)
{
    u8 i, n;
    for(i = 0; i < 8; i++) {
        for(n = 0; n < 128; n++)
            OLED_GRAM[n][i] = 0x00;
    }
    OLED_Refresh_Gram();//update display
}


////////////////////////////////////////////////////////////////////////////////
/// @brief  draw point
/// @param  x:0~127; y:0~63; t :1, fill in. 0, empty out.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void OLED_DrawPoint(u8 x, u8 y, u8 t)
{
    u8 pos, bx, temp = 0;
    if(x > 127 || y > 63)return; //out of range.
    pos = 7 - y / 8;
    bx = y % 8;
    temp = 1 << (7 - bx);
    if(t)OLED_GRAM[x][pos] |= temp;
    else OLED_GRAM[x][pos] &= ~temp;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief The diagonal coordinates of the region filled by x1,y1,x2,y2
/// @note  make sure the x1 < = x2; y1<=y2 0<=x1<=127 0<=y1<=63
///        dot: 0, empty; 1, filling,
/// @param x1,y1,x2,y2,dot: The data to be written
/// @retval None.
////////////////////////////////////////////////////////////////////////////////

void OLED_Fill(u8 x1, u8 y1, u8 x2, u8 y2, u8 dot)
{
    u8 x, y;
    for(x = x1; x <= x2; x++) {
        for(y = y1; y <= y2; y++)OLED_DrawPoint(x, y, dot);
    }
    OLED_Refresh_Gram();
}
//

////////////////////////////////////////////////////////////////////////////////
/// @brief Displays a character, including partial characters, at the specified location
/// @param  x:0~127; y:0~63; Mode :0, anti-white display; 1. Normal display
///         Size: Select the font 12/16/24
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void OLED_ShowChar(u8 x, u8 y, u8 chr, u8 size, u8 mode)
{
    u8 temp, t, t1;
    u8 y0 = y;
    u8 csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2); //Gets the number of bytes of a character corresponding to the font set
    chr = chr - ' ';  // Get the offset value
    for(t = 0;  t < csize;  t++) {
        if(size == 12)temp = asc2_1206[chr][t];      // Call the 1206 font
        else if(size == 16)temp = asc2_1608[chr][t];  // Call the font 1608
        else if(size == 24)temp = asc2_2412[chr][t];  // Call the 2412 font
        else return;                                 // There is no word library
        for(t1 = 0; t1 < 8; t1++) {
            if(temp & 0x80)OLED_DrawPoint(x, y, mode);
            else OLED_DrawPoint(x, y, !mode);
            temp <<= 1;
            y++;
            if((y - y0) == size) {
                y = y0;
                x++;
                break;
            }
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  M to the NTH powert
/// @param  m,n
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
u32 mypow(u8 m, u8 n)
{
    u32 result = 1;
    while(n--)result *= m;
    return result;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief Display 2 numbers
/// @param x,y: starting coordinates; Len: The number of digits; Size: Font size
///        num: values (0 ~ 4294967295);
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void OLED_ShowNum(u8 x, u8 y, u32 num, u8 len, u8 size)
{
    u8 t, temp;
    u8 enshow = 0;
    for(t = 0; t < len; t++) {
        temp = (num / mypow(10, len - t - 1)) % 10;
        if(enshow == 0 && t < (len - 1)) {
            if(temp == 0) {
                OLED_ShowChar(x + (size / 2)*t, y, ' ', size, 1);
                continue;
            }
            else enshow = 1;

        }
        OLED_ShowChar(x + (size / 2)*t, y, temp + '0', size, 1);
    }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Displays strings
/// @param x,y:starting coordinates; Size: Font size; P: string starting address
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void OLED_ShowString(u8 x, u8 y, const u8* p, u8 size)
{
    while((*p <= '~') && (*p >= ' ')) { //Judge if the character is illegal!
        if(x > (128 - (size / 2))) {
            x = 0;
            y += size;
        }
        if(y > (64 - size)) {
            y = x = 0;
            OLED_Clear();
        }
        OLED_ShowChar(x, y, *p, size, 1);
        x += size / 2;
        p++;
    }

}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Initilaze OLED
/// @param  None
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void OLED_Init(void)
{
    OLED_WR_Byte(0xAE, OLED_CMD);  // Turn off display
    OLED_WR_Byte(0xD5, OLED_CMD);  // Set the clock frequency division factor and oscillation frequency
    OLED_WR_Byte(0x50, OLED_CMD);  //[3:0], frequency division factor; [7:4], the oscillation frequency
    OLED_WR_Byte(0xA8, OLED_CMD);  // Set the number of driving routes
    OLED_WR_Byte(0X3F, OLED_CMD);  // the default 0 x3f (1/64)
    OLED_WR_Byte(0xD3, OLED_CMD);  // Set display offset
    OLED_WR_Byte(0X00, OLED_CMD);  // Defaults to 0

    OLED_WR_Byte(0x40, OLED_CMD);  // Set to display the start line [5:0], the number of lines.

    OLED_WR_Byte(0x8D, OLED_CMD);  // Charge pump setup
    OLED_WR_Byte(0x14, OLED_CMD);  //bit2, on/off
    OLED_WR_Byte(0x20, OLED_CMD);  // Set the memory address mode
    OLED_WR_Byte(0x02, OLED_CMD);  //[1:0],00, column address mode; 01, line address mode; 10. Page address mode; The default 10;
    OLED_WR_Byte(0xA1, OLED_CMD);  // section redefine setting,bit0:0,0->0; 1, 0 - > 127;
    OLED_WR_Byte(0xC0, OLED_CMD);  // Set COM scanning direction; Bit3 :0, normal mode; 1, redefine the schema COM[n-1]->COM0; N: Number of driving routes
    OLED_WR_Byte(0xDA, OLED_CMD);  // Set COM hardware pin configuration
    OLED_WR_Byte(0x12, OLED_CMD);  // [and] configuration

    OLED_WR_Byte(0x81, OLED_CMD);  // Contrast Settings
    OLED_WR_Byte(0xEF, OLED_CMD);  // 1 ~ 255; Default 0X7F (brightness setting, larger, brighter)
    OLED_WR_Byte(0xD9, OLED_CMD);  // Set the pre-charge cycle
    OLED_WR_Byte(0xf1, OLED_CMD);  //[3:0],PHASE 1; [7:4],PHASE 2;
    OLED_WR_Byte(0xDB, OLED_CMD);  // Set VCOMH voltage multiplier
    OLED_WR_Byte(0x30, OLED_CMD);  // 000,0.65 /// VCC (6:4); 001,0.77 /// VCC. 011,0.83 /// VCC.

    OLED_WR_Byte(0xA4, OLED_CMD);  // Global display on; Bit0:1, open; 0, close; (White/black)
    OLED_WR_Byte(0xA6, OLED_CMD);  // Set display mode; Bit0 :1, inverting display; 0, normal display
    OLED_WR_Byte(0xAF, OLED_CMD);  // Turn on display

    OLED_Clear();
}

/// @}

/// @}

/// @}
